#include <vector>
#include <iostream>

using namespace std;

#define ON  if (1)
#define OFF if (0)
#define N   10
#define OUT(arr, msg) do{ \
    cout << msg; \
    for (size_t i = 0; i < arr.size(); i++) cout << arr[i] << " "; \
    cout << endl; \
}while(0)

int main(int argc, char const *argv[])
{
    /*****************************************************************************************************
     * vector 序列容器
     * ---------------------------------------------------------------------------------------------------
     * 相比较array， vector是动态增减元素个数的， 可以进行插入和删除元素
     *****************************************************************************************************/
    // -----------------------------------------------
    // --- 定义 ----
    // -----------------------------------------------
    OFF
    {
        // 默认定义， 不分配空间
        vector<int> nums;
    }
    
    OFF
    {
        // 指定元素个数
        // 注意： 与array不同， 这样定义的vector序列会自动初始化为0
        vector<int> nums(N);
        OUT(nums, "序列: ");
    }
    
    OFF
    {
        // 指定元素个数，并指定初始值
        vector<int> nums(N, 7);
        OUT(nums, "序列: ");
    }

    OFF
    {
        // 定义时初始化值
        // 注意： 与array不同， vector没有局部初始化的概念， 所以不能写作 vector<int> nums_c(10) {10, 20} 
        vector<int> nums {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
        OUT(nums, "序列: ");
    }
    

    /*****************************************************************************************************
     * 成员函数
     * ---------------------------------------------------------------------------------------------------
     * ********** 返回迭代器 **********
     * 
     * vector.begin()               返回:随机访问迭代器  首元素位置指针   
     * 
     * vector.end()                 返回:随机访问迭代器  末尾元素后面位置指针  
     * 
     * vector.rbegin()              返回:随机访问迭代器  末尾元素位置指针, 反向迭代器  
     * 
     * vector.rend()                返回:随机访问迭代器  首元素之前位置指针, 反向迭代器
     * 
     * vector.cbegin()              返回:随机访问迭代器  首元素位置指针, 不能通过指针修改值
     * 
     * vector.cend()                返回:随机访问迭代器  末尾元素后面位置指针, 不能通过指针修改值
     * 
     * vector.crbegin()             返回:随机访问迭代器  末尾元素位置指针, 反向迭代器, 不能通过指针修改值  
     * 
     * vector.crend()               返回:随机访问迭代器  首元素之前位置指针, 反向迭代器, 不能通过指针修改值
     * 
     * 
     * ********** 容量 **********
     * 
     * vector.size() 	            返回: vector中元素个数
     * 
     * vector.max_size() 	        返回: vector可容纳最大个数
     * 
     * vector.empty() 	            返回: 元素个数是否为0
     * 
     * vector.resize()              改变容器的大小
     * 
     * vector.capacity()            获取系统当前为容器开辟的空间大小
     * 
     * vector.reserve()             修改系统为容器开辟的空间大小
     * 
     * vector.shrink_to_fit()       缩小容器占用空间到容器实际大小
     * 
     * 
     * ********** 访问成员 **********
     * vector[]                     使用 [] 操作符可以直接访问对应下标的成员
     * 
     * vector.at(n) 	            返回: 容器中 n 位置处元素的引用，该函数自动检查 n 是否在有效的范围内，如果不是则抛出 out_of_range 异常。
     * 
     * vector.front() 	            返回: 容器中第一个元素的直接引用，该函数不适用于空的 vector 容器。
     * 
     * vector.back()                返回容器中最后一个元素的直接应用，该函数同样不适用于空的 vector 容器。
     * 
     * vector.data()                返回一个指向容器首个元素的指针。利用该指针，可实现复制容器中所有元素等类似功能。
     * 
     * ********** 修改成员 **********
     * vector.assign()              给容器整体赋值
     * 
     * vector.push_back()           向容器尾部添加元素
     * 
     * vector.pop_back()            弹出容器尾部的元素
     * 
     * vector.insert()              指定位置插入一个或多个元素
     * 
     * vector.erase()               移除容器中的一个或多个元素
     * 
     * vector1.swap(vector2) 	    交换 vector1 和 vector2 容器中的所有元素, 类型必须相同， 大小可以不同
     * 
     * vector.clear()               清空容器
     * 
     * vector.emplace()             指定位置插入一个元素， 高效版的insert
     * 
     * vector.emplace_back()        尾插一个元素， 高效版的push_back
     * 
     * 
     * **********  **********
     * 
     * vector.get_allocator         复制一份vector的内存分配器
     *****************************************************************************************************/
    

    // vector.begin() 
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        vector<int>::iterator p = nums.begin();
        OUT(nums, "序列: ");
        cout << "vector.begin() 位置的元素: " << *p << endl;
    }

    // vector.end()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        vector<int>::iterator p = nums.end();
        p--;
        cout << "vector.end() 之前位置的元素: " << *p << endl;

        cout << "结合使用迭代器 begin 和 end 遍历vector: " << endl;
        for (vector<int>::iterator i = nums.begin(); i < nums.end(); i++) 
            cout << *i << " ";
        cout << endl;
    }

    // vector.rbegin()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        // 注意， r开头的迭代器函数返回值类型是反向迭代器类型， reverse_iterator
        // 反向迭代器的 + 和 - 操作与正常的指针操作都是相反的
        vector<int>::reverse_iterator q = nums.rbegin();
        cout << "vector.rbegin() 位置的元素" << *q << endl;
    }

    // vector.rend()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        vector<int>::reverse_iterator q = nums.rend();
        q--;
        cout << "vector.rend() 挪动一位之后的元素: " << *q << endl;
    }

    // vector.cbegin() 
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        // 指针位置与 begin() 相同， 不同在于增加了const属性， 不能通过指针修改值
        vector<int>::const_iterator p = nums.cbegin();
        cout << "vector.cbegin() 位置的元素: " << *p << endl;
    }

    // vector.cend() 
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        // 指针位置与 end() 相同， 不同在于增加了const属性， 不能通过指针修改值
        vector<int>::const_iterator p = nums.cend();
        p--;
        cout << "vector.cend() 之前位置的元素: " << *p << endl;
    }
    

    // vector.crbegin()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        // 指针位置与 rbegin() 相同， 不同在于增加了const属性， 不能通过指针修改值
        // 注意， r开头的迭代器函数返回值类型是反向迭代器类型， reverse_iterator
        // 反向迭代器的 + 和 - 操作与正常的指针操作都是相反的
        vector<int>::const_reverse_iterator p = nums.crbegin(); 
        cout << "vector.crbegin() 位置的元素" << *p << endl;
    }
    

    // vector.crend()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        // 指针位置与 rend() 相同， 不同在于增加了const属性， 不能通过指针修改值
        vector<int>::const_reverse_iterator p = nums.crend();
        p--;
        cout << "vector.crend() 位置移动一位之后的的元素: " << *p << endl;
    }
    

    // vector.size()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20};
        OUT(nums, "序列: ");
        cout << "vector.size() : " << nums.size() << endl;
    }


    // vector.max_size()
    // -----------------------------------------------
    // 根据系统和库的限制范围内的最大值
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        cout << "vector.max_size() : " << nums.max_size() << endl;
    }
    

    // vector.resize()
    // -----------------------------------------------
    // 改的比原来容量小时， 会删除掉多余的数据
    // 改的标原来大时， 默认填充0， 指定第二个参数时， 使用第二个参数填充容器
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        nums.resize(4);
        cout << "after vector.max_size(4) : " << nums.size() << endl;
        nums.resize(10, 99);
        cout << "after nums.resize(10, 99) : " << nums.size() << endl;
        OUT(nums, "序列: ");
    }
    

    // vector.capacity() 
    // -----------------------------------------------
    // size 是当前容器实际元素个数
    // capacity 是容器当前申请的空间大小， 单位是元素个数
    OFF
    {
        typedef struct {
            int     a;
            char    b;
            int     c[20];
        } num_t;

        vector<num_t> nums{{50}, {10}, {40}, {20}};

        nums.push_back({22});
        cout << "nums.capacity(): " << nums.capacity() << endl;
        cout << "nums.size(): " << nums.size() << endl;
    }


    // vector.reserve()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{19};
        cout << "nums.capacity(): " << nums.capacity() << endl;
        cout << "nums.size(): " << nums.size() << endl;

        nums.reserve(4);
        cout << "nums.reserve(4) ==> nums.capacity(): " << nums.capacity() << endl;
        cout << "nums.reserve(4) ==> nums.size(): " << nums.size() << endl;
    }


    // vector.shrink_to_fit()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums(100);
        cout << "nums.size: " << nums.size() << " nums.capacity: " << nums.capacity() << endl;

        nums.resize(15);
        cout << "nums.resize(15)" << endl;
        cout << "nums.size: " << nums.size() << " nums.capacity: " << nums.capacity() << endl;

        nums.shrink_to_fit();
        cout << "nums.shrink_to_fit()" << endl;
        cout << "nums.size: " << nums.size() << " nums.capacity: " << nums.capacity() << endl;
    }


    // vector.empty()
    // -----------------------------------------------
    // 这个值和 (vector.size() == 0)返回的是相同的， 但是，使用empty效率会更高
    OFF
    {
        vector<int> empty_arr{};
        OUT(empty_arr, "序列:");
        cout << "vector.empty() : " << empty_arr.empty() << endl;
        vector<int> nums{50, 10, 40, 20};
        OUT(nums, "序列: ");
         cout << "vector.empty() : " << nums.empty() << endl;
    }
    

    // vector.at(n)
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "序列: ");
        // at中返回的元素是vector[下标]号元素
        cout << "vector.at(5) : " << nums.at(5) << endl;
    }
    
    
    // vector.front()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        cout << "front of nums: " << nums.front() << endl;
    }


    // vector.back()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        cout << "back of nums: " << nums.back() << endl;
    }


    // vector.data()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "nums: ");
        int *p = nums.data();
        cout << *p << " " << *(++p) << endl;
    }


    // vector.assign()
    // -----------------------------------------------
    // 容器赋值有3种构造函数， 也就意味着有3种赋值方法
    // 1. 使用初始化表 initializer_list 赋值， 每使用{}构造初始化表时， 都会实例化一个initializer_list对象
    // 2. 使用给定的值填充赋值, 第一个参数是填充个数， 第二个值是所填充的值
    // 3. 使用其他容器的一段赋值， 第一个参数是其他容器的开始， 第二个参数是其他容器的结尾
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        initializer_list<int> a{1, 4, 5, 7, 12,88,9, 9,9 ,9 };
        vector<int> first;
        vector<int> second;
        vector<int> third;

        // 1. 使用初始化表赋值
        first.assign({1, 3, 5, 7, 9});
        OUT(first, "vector 1: ");

        // 2. 使用给定的值填充赋值
        second.assign(3, 10);
        OUT(second, "vector 2: ");

        // 3. 使用其他容器的一段来赋值
        third.assign(nums.begin() + 1, nums.end() - 1);
        OUT(third, "vector 3: ");
    }


    // vector.push_back()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums;
        for (size_t i = 0; i < N; i++) nums.push_back(i * 10);
        
        OUT(nums, "after push_back: ");
    }


    // vector.pop_back()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "vector: ");
        cout << "after pop_back " << nums.back() << endl;
        nums.pop_back();
        
        OUT(nums, "vector: ");
    }


    // vector.insert()
    // -----------------------------------------------
    // 指定位置插入元素有5种插入方式
    // 1. 直接插入值
    // 2. 使用指定的值填充
    // 3. 取其他容器的一段填充
    // 4. 调用移动构造函数进行填充
    //      这里和直接插入值得区别是， 只要原值是const类型的， 那么调用的就是拷贝构造， 如果原值非const类型， 那调用的就是移动构造
    // 5. 初始化表插入
    {
        // 方式1： 直接插入值
        OFF {
            vector<int> nums{10, 20, 30};
            vector<int>::iterator it = nums.begin();
            OUT(nums, "vector: ");
            
            nums.insert(it, 101);        
            OUT(nums, "vector: ");
        }
        
        // 方式2： 使用指定值填充
        OFF {
            vector<int> nums{10, 20, 30};
            vector<int>::iterator it = nums.begin();
            OUT(nums, "vector: ");

            const int a = 102;
            nums.insert(it + 1, 3, 102);
            OUT(nums, "vector: ");
        }
        
        // 方式3： 取其他容器的一段进行填充
        OFF {
            vector<int> nums{10, 20, 30};
            vector<int>::iterator it = nums.begin();
            vector<int> nums_fill{11, 22, 33, 44, 55};
            OUT(nums, "vector: ");

            nums.insert(it + 1, nums_fill.begin() + 1, nums_fill.end() - 1);
            OUT(nums, "vector: ");
        }

        // 方式4： 调用移动构造函数进行填充
        OFF {
            vector<int> nums{10, 20, 30};
            vector<int>::iterator it = nums.begin();
            OUT(nums, "vector: ");

            int a = 1000;
            nums.insert(it + 1, a);
            OUT(nums, "vector: ");
        }

        // 方式5： 使用初始化表插入
        OFF {
            vector<int> nums{10, 20, 30};
            vector<int>::iterator it = nums.begin();
            OUT(nums, "vector: ");

            nums.insert(it + 1, {11, 22, 33});
            OUT(nums, "vector: ");
        }
    }

    // vector.earse()
    // -----------------------------------------------
    // 1. 移除单个元素
    // 2. 移除多个元素
    {
        // 移除单个元素
        OFF {
            vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
            OUT(nums, "nums: ");
            nums.erase(nums.begin() + 2);
            cout << "after earse(nums.begin() + 2) " << endl;
            OUT(nums, "nums: ");
        }

        // 移除多个元素
        OFF {
            vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
            OUT(nums, "nums: ");
            nums.erase(nums.begin() + 1, nums.end() - 1);
            cout << "after earse(nums.begin() + 1, nums.end() - 1) " << endl;
            OUT(nums, "nums: ");
        }
    }


    // vector1.swap(vector2)
    // -----------------------------------------------
    OFF
    {
        vector<int> va{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        vector<int> vb{100, 200, 300};
        OUT(va, "va: ");
        OUT(vb, "vb: ");

        va.swap(vb);
        cout << "after va.swap(vb)" << endl;
        OUT(va, "va: ");
        OUT(vb, "vb: ");
    }


    // vector.clear()
    // -----------------------------------------------
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        cout << "nums size: " << nums.size() << endl;
        nums.clear();
        cout << "nums size: " << nums.size() << endl;
    }


    // vector.emplace()
    // -----------------------------------------------
    // 可以看做是高效版的insert
    // 与 insert 不同的是， insert插入新元素时会调用vector的拷贝构造或移动构造函数， 此时会产生中间变量
    // 而 emplace 不会用到拷贝或者移动构造， 而是直接构造， 不会产生中间变量， 因此比insert的执行效率要高
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "nums: ");

        nums.emplace(nums.begin(), 90);
        OUT(nums, "nums: ");
    }


    // vector.emplace_back()
    // -----------------------------------------------
    // 与emplace一样， 使用emplace_back进行尾插的好处是避免产生中间变量， 使得插入更高效
    OFF
    {
        vector<int> nums{50, 10, 40, 20, 60, 70, 100, 80, 90, 30};
        OUT(nums, "nums: ");

        nums.emplace_back(100101);
        OUT(nums, "nums: ");
    }


    // vector.get_allocator()
    // -----------------------------------------------
    // 复制一份vector内存分配器
    // 用途：……
    OFF
    {
        vector<int> nums;
        int *p;
        p = nums.get_allocator().allocate(10);
        p[5] = 200;
    }

    return 0;
}
